<html>
<head><meta charset="utf-8"><title>to-pin-or-not-to-pin · wg-async-foundations/stream-trait-rfc · Zulip Chat Archive</title></head>
<h2>Stream: <a href="https://rust-lang.github.io/zulip_archive/stream/249502-wg-async-foundations/stream-trait-rfc/index.html">wg-async-foundations/stream-trait-rfc</a></h2>
<h3>Topic: <a href="https://rust-lang.github.io/zulip_archive/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin.html">to-pin-or-not-to-pin</a></h3>

<hr>

<base href="https://rust-lang.zulipchat.com">

<head><link href="https://rust-lang.github.io/zulip_archive/style.css" rel="stylesheet"></head>

<a name="204575728"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin/near/204575728" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> nikomatsakis <a href="https://rust-lang.github.io/zulip_archive/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin.html#204575728">(Jul 21 2020 at 17:15)</a>:</h4>
<p>So I want to pick up the <a href="https://github.com/rust-lang/wg-async-foundations/pull/15#discussion_r452482084">conversation we were having here</a>. I'd like to include some comments on why <code>next</code> requires <code>Self: Unpin</code> and why we expect that streams should have <code>poll_next</code> require pinning. I was talking to <span class="user-mention" data-user-id="225192">@Nell Shamrell-Harrington</span> about it just now, I'll try to lay out what I think are the major considerations (well, I will in a bit...)</p>



<a name="204600103"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin/near/204600103" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> nikomatsakis <a href="https://rust-lang.github.io/zulip_archive/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin.html#204600103">(Jul 21 2020 at 20:37)</a>:</h4>
<p>Right, so, I think you could either have <code>next</code> take <code>Pin&lt;&amp;mut Self&gt;</code> or <code>&amp;mut self</code>. </p>
<p>Taking <code>Pin&lt;&amp;mut Self&gt;</code> would mean that it can call <code>poll_next</code> directly but would require that all callers manually pin things.</p>
<p>Taking <code>&amp;mut self</code> means that the <code>next</code> method "pins" the <code>&amp;mut Self</code> reference that it has, but this pin is meaningless (since once the <code>&amp;mut Self</code> borrow expires, the original <code>Self</code> value can be moved). This is why it would not type check without <code>where Self: Unpin</code>. </p>
<p>For streams that are <code>Unpin</code>, having <code>next</code> be <code>&amp;mut self</code> is ergonomically better, because it avoids the need to pin before calling <code>next</code>.</p>
<p>For streams that are not <code>Unpin</code> (very few today, but perhaps more at some point because of <code>async gen fn</code> syntax), this means that to call <code>next</code>, one must first pin explicitly. But you would have had to do that anyway. </p>
<p>So, making <code>next</code> take <code>&amp;mut self</code>, with <code>Self: Unpin</code> is strictly more ergonomic.</p>
<p>Does this sound correct?</p>



<a name="204601226"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin/near/204601226" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> eddyb <a href="https://rust-lang.github.io/zulip_archive/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin.html#204601226">(Jul 21 2020 at 20:49)</a>:</h4>
<p>presumably you can easily create <code>!Unpin</code> streams by using a stream combinator/adapter with an <code>async fn</code>?</p>



<a name="204601297"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin/near/204601297" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> eddyb <a href="https://rust-lang.github.io/zulip_archive/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin.html#204601297">(Jul 21 2020 at 20:50)</a>:</h4>
<p>if streams have a <code>map</code>, that's probably the easiest way to make an example</p>



<a name="204601481"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin/near/204601481" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> eddyb <a href="https://rust-lang.github.io/zulip_archive/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin.html#204601481">(Jul 21 2020 at 20:52)</a>:</h4>
<p><span class="user-mention" data-user-id="116009">@nikomatsakis</span> am I missing something? everyone keeps talking about async generators but "surely" you can end up with this due to combinators?</p>



<a name="204601594"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin/near/204601594" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> eddyb <a href="https://rust-lang.github.io/zulip_archive/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin.html#204601594">(Jul 21 2020 at 20:53)</a>:</h4>
<p>(also I was wondering what's the difference between <code>next</code> and <code>poll_next</code>, looks like <code>next</code> returns a future, so <code>.next().await</code> vs a lower-level desugaring which would use <code>poll_next</code> in a loop I guess?)</p>



<a name="204601663"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin/near/204601663" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> eddyb <a href="https://rust-lang.github.io/zulip_archive/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin.html#204601663">(Jul 21 2020 at 20:54)</a>:</h4>
<p>also I think I only saw this stream because it was created and I got automatically subscribed to it?</p>



<a name="204633893"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin/near/204633893" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Matthias247 <a href="https://rust-lang.github.io/zulip_archive/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin.html#204633893">(Jul 22 2020 at 06:25)</a>:</h4>
<p><span class="user-mention" data-user-id="116009">@nikomatsakis</span> We have <code>!Unpin</code> streams - e..g the Stream here is one: <a href="https://github.com/Matthias247/futures-intrusive/blob/master/src/channel/mpmc.rs#L565-L625">https://github.com/Matthias247/futures-intrusive/blob/master/src/channel/mpmc.rs#L565-L625</a></p>
<p>Those lines basically implement a <code>Fn() -&gt; Future</code> -&gt; Stream adapter, since people seem to like interacting with channels via Streams instead of async fns. The adapter generates a <code>Future + !Unpin</code> when the Stream is polled, stores it in the Stream itself, and then polls that <code>Future</code> until it resolves. When that is done the same process repeats. Since the stored <code>Future</code> needs to be pinned the Stream needs to be the same. </p>
<p>We also talked about similar Streams that are required inside tokio. However I don't fully recall if we added those already or not</p>



<a name="204685069"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin/near/204685069" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> boats <a href="https://rust-lang.github.io/zulip_archive/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin.html#204685069">(Jul 22 2020 at 15:55)</a>:</h4>
<blockquote>
<p>Does this soud correct?</p>
</blockquote>
<p>Yes I think that's correct.</p>



<a name="204685272"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin/near/204685272" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> boats <a href="https://rust-lang.github.io/zulip_archive/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin.html#204685272">(Jul 22 2020 at 15:56)</a>:</h4>
<p>Basically I think we will want some sort of for await syntax which does not require Unpin for this reason</p>



<a name="204693259"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin/near/204693259" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> nikomatsakis <a href="https://rust-lang.github.io/zulip_archive/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin.html#204693259">(Jul 22 2020 at 17:00)</a>:</h4>
<p>I didn't mean to imply that there are <em>no</em> <code>Unpin</code> streams, just that they are relatively unusual today.</p>



<a name="204719395"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin/near/204719395" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Matthias247 <a href="https://rust-lang.github.io/zulip_archive/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin.html#204719395">(Jul 22 2020 at 20:35)</a>:</h4>
<p>That's true. In a lot of cases the problem can also be solved by boxing the interior state. For streams I would typically be OK with it, since those are long-lived, and so we don't have short-lived allocations (e.g. per IO operation).</p>



<a name="204719542"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin/near/204719542" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Matthias247 <a href="https://rust-lang.github.io/zulip_archive/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin.html#204719542">(Jul 22 2020 at 20:37)</a>:</h4>
<p>There are only certain domains were allocations are problematic in general - e.g. embedded. Since futures-intrusive aims at that domain it's helpful being able to avoid the allocation.<br>
but I guess if that would not be possible I would simply recommend people not to use <code>Stream</code> and just stay with <code>async fn</code>s (or functions that return <code>Future</code>s)</p>



<a name="204719806"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin/near/204719806" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Matthias247 <a href="https://rust-lang.github.io/zulip_archive/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin.html#204719806">(Jul 22 2020 at 20:39)</a>:</h4>
<p>Since other IO primitives like <code>AsyncRead/Write</code> where mentioned on the thread: I've never had any use of those where the implementation at the end wasn't a state-machine that you would need to write by hand anyway. Whether it's an OS socket adapter, a TLS library adapter, a stream compression library, a HTTP/2 library, etc.<br>
Therefore I think having stayed with <code>&amp;mut self</code> would have been fine.</p>
<p>In fact that is what we are currently doing with a higher level library which is also making use <code>poll_read/poll_write</code> like calls. They just take <code>&amp;mut self</code>, since <code>Pin</code> just confuses team members and doesn't add benefit (until maybe in a very distant future - but then we can refactor too)</p>



<a name="205171290"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin/near/205171290" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> nikomatsakis <a href="https://rust-lang.github.io/zulip_archive/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin.html#205171290">(Jul 27 2020 at 21:38)</a>:</h4>
<p><span class="user-mention silent" data-user-id="119009">eddyb</span> <a href="#narrow/stream/249502-wg-async-foundations.2Fstream-trait-rfc/topic/to-pin-or-not-to-pin/near/204601226">said</a>:</p>
<blockquote>
<p>presumably you can easily create <code>!Unpin</code> streams by using a stream combinator/adapter with an <code>async fn</code>?</p>
</blockquote>
<p>I think <span class="user-mention" data-user-id="119009">@eddyb</span> this is a good point, although the <a href="https://docs.rs/futures/0.3.5/futures/stream/trait.StreamExt.html#method.map">map</a> from the futures crate doesn't actually fit that pattern. But if we had async closures it would, I suppose. (This is exactly why we're not yet adding these combinators...)</p>



<a name="207124006"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin/near/207124006" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Nemo157 <a href="https://rust-lang.github.io/zulip_archive/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin.html#207124006">(Aug 17 2020 at 09:42)</a>:</h4>
<p>The <code>async</code> map function is <a href="https://docs.rs/futures/0.3.5/futures/stream/trait.StreamExt.html#method.then"><code>then</code></a>: &lt;<a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2018&amp;gist=22693976b3b34748f6898609869f186c">https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2018&amp;gist=22693976b3b34748f6898609869f186c</a>&gt;</p>



<a name="208284165"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin/near/208284165" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Nemo157 <a href="https://rust-lang.github.io/zulip_archive/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin.html#208284165">(Aug 27 2020 at 22:25)</a>:</h4>
<p><span class="user-mention silent" data-user-id="204219">Matthias247</span> <a href="#narrow/stream/249502-wg-async-foundations.2Fstream-trait-rfc/topic/to-pin-or-not-to-pin/near/204719806">said</a>:</p>
<blockquote>
<p>Since other IO primitives like <code>AsyncRead/Write</code> where mentioned on the thread: I've never had any use of those where the implementation at the end wasn't a state-machine that you would need to write by hand anyway. Whether it's an OS socket adapter, a TLS library adapter, a stream compression library, a HTTP/2 library, etc.<br>
Therefore I think having stayed with <code>&amp;mut self</code> would have been fine.</p>
</blockquote>
<p>I finally got round to completing my prototype of <code>AsyncRead</code> defined using generators <a href="https://github.com/Nemo157/async-io-macros">https://github.com/Nemo157/async-io-macros</a>. You can see an example of how much it simplifies <a href="https://github.com/Nemo157/async-compression/blob/74125e60cafafbedddadda2b2bd1b10cb89ac4ab/src/futures/bufread/generic/encoder.rs#L54-L113">this state machine</a> down to <a href="https://github.com/Nemo157/async-compression/blob/adc3d807980378520b712a4d5f7752b64abed7d3/src/futures/bufread/generic/encoder.rs#L18-L48">this little generator</a>. (<code>AsyncWrite</code> seems much more difficult to work the ability to flush into it, but hopefully I'll spend some time seeing if it's possible soon).</p>



<a name="208451948"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin/near/208451948" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Matthias247 <a href="https://rust-lang.github.io/zulip_archive/stream/249502-wg-async-foundations/stream-trait-rfc/topic/to-pin-or-not-to-pin.html#208451948">(Aug 29 2020 at 20:17)</a>:</h4>
<p><span class="user-mention" data-user-id="210267">@Nemo157</span> In this case I agree it looks nice!</p>
<p>But fun fact: I actually moved back from implementing a HTTP/2 version using async/await to using a bare-state machine in the last couple of weeks. <br>
The challenges I had with async/await</p>
<ol>
<li>too much forced synchronization between functionality and</li>
<li>I saw no way forward providing zero-cost bindings for it for people not using Rust because we can't store async-await generated futures without boxing and due to <code>Waker</code> requirements of being <code>Clone + Send + Sync</code>.</li>
</ol>
<p>essentially the story is that HTTP/2 offers N pair of <code>AsyncRead + AsyncWrite</code> streams (for each request), plus one more pair for the underlyign TLS connection. With async/await I modelled that as one connection read task, one  connection write task, some shared state that is accessed from read/write and connection tasks in a synchronized fashion. Some thing here - like updating something in the writer task if the reader received a certain message where really rather heavy-handed and required far more synchronization than I would have liked.<br>
Now with one big state-machine for the whole thing this gets easy, since I can access all the mutable state at once - but some ergonomics are now definitely lacking compared to writing things using async/await syntax :(</p>



<hr><p>Last updated: Aug 07 2021 at 22:04 UTC</p>
</html>